/*
 * yBlockingQueue.cpp
 *
 *  Created on: Sep 17, 2016
 *      Author: root
 */

#include "yBlockingQueue.h"

BlockingQueue::BlockingQueue() {
	capacity = 10;
	queue = new void*[capacity];
	head = 0, tail = 0;
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&notFull, NULL);
	pthread_cond_init(&notEmpty, NULL);

}

BlockingQueue::BlockingQueue(int cap) {
	capacity = cap;
	queue = (void**) malloc(sizeof(void*));
	cout << "capacity " << sizeof(queue) << endl;
	head = 0, tail = 0;
	pthread_mutex_init(&mutex, NULL);
	pthread_cond_init(&notFull, NULL);
	pthread_cond_init(&notEmpty, NULL);

}

BlockingQueue::~BlockingQueue() {
	int i = tail;
	while (i++ != head) {
		free(queue[i]);
	}
	capacity = 0;
	head = 0, tail = 0;

	free(queue);
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&notFull);
	pthread_cond_destroy(&notEmpty);
}

void BlockingQueue::put(void* item) {
	pthread_mutex_lock(&mutex);
	cout << "you want push " << item << endl;
	while ((head + 1) % capacity == tail) {
		cout << "is full,wait..." << endl;
// push wait
		pthread_cond_wait(&notFull, &mutex);
		cout << "not full,unlock" << endl;
	}

	queue[head] = item;
	head = (head + 1) % capacity;
	cout << "push " << item << endl;
//wake up poll thread
	pthread_cond_signal(&notEmpty);
	pthread_mutex_unlock(&mutex);
}

void* BlockingQueue::take() {
	pthread_mutex_lock(&mutex);
	void* ret = NULL;
	while (head == tail) {
		cout << "is empty,wait..." << endl;
//poll wait
		pthread_cond_wait(&notEmpty, &mutex);
		cout << "not empty,unlock..." << endl;
	}

	ret = queue[tail];
	tail = (tail + 1) % capacity;
	cout << "take " << ret << endl;
//wake up push thread
	pthread_cond_signal(&notFull);
	pthread_mutex_unlock(&mutex);
	return ret;
}

